/**
 * 绘图工具 by zuozhengqi 2016/12/08
 */
import d3 from 'd3'
import moment from "moment";
import icons from './icons'

// import {numAdd, numSub, numMulti, numDiv} from './util'
// 输出到控制
export function log(key, val) {
  if (val) {
    console.log(key, val)
  } else {
    console.log(key)
  }
}

// 按对象属性排序比较函数(顺排)
export function compare(propertyName) {
  return function (object1, object2) {
    let value1 = object1[propertyName]
    let value2 = object2[propertyName]
    if (value2 < value1) {
      return 1
    } else if (value2 > value1) {
      return -1
    } else {
      return 0
    }
  }
}

// 按对象属性排序比较函数(倒排)
export function compareASC(propertyName) {
  return function (object1, object2) {
    let value1 = object1[propertyName]
    let value2 = object2[propertyName]
    if (value2 > value1) {
      return 1
    } else if (value2 < value1) {
      return -1
    } else {
      return 0
    }
  }
}

// 简体中文本地化
export let zh = d3.locale({
  decimal: '.',
  thousands: ',',
  grouping: [3],
  currency: ['¥', ''],
  dateTime: '%a %b %e %X %Y',
  date: '%Y/%-m/%-d',
  time: '%H:%M:%S',
  tipTime: '%m/%d %H:%M',
  periods: ['上午', '下午'],
  days: ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'],
  shortDays: ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'],
  months: ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月'],
  shortMonths: ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月']
})

// 格式化时间样式
export const timerStyle = {
  Ymd: '%Y/%m/%d',
  md: '%m/%d',
  YmdHM: '%Y/%m/%d %H:%M',
  YmdHMS: '%Y/%m/%d %H:%M:%S',
  mdHM: '%m/%d %H:%M',
  HMS: '%H:%M:%S'
}

// 格式化时间
// export function formatTime (style) {
//   return d3.time.format(style)
// }

// 格式化时间(兼容模式 with moment)
export function formatTime(style) {
  switch (style) {
    case timerStyle.Ymd:
      return momentFortmater('YYYY/MM/DD');
    case timerStyle.md:
      return momentFortmater('MM/DD');
    case timerStyle.YmdHM:
      return momentFortmater('YYYY/MM/DD HH:mm');
    case timerStyle.YmdHMS:
      return momentFortmater('YYYY/MM/DD HH:mm:ss');
    case timerStyle.mdHM:
      return momentFortmater('MM/DD HH:mm');
    case timerStyle.HMS:
      return momentFortmater('HH:mm:ss');
    default:
      return d3.time.format(style);
  }
}

// moment 格式化日期时间 for windows IE/Edge
function momentFortmater(template) {
  let n = template.length;
  function formater(date) {
    let momentDate = moment(date);
    // console.debug('momentFortmater: ', template, date, momentDate);
    return (!momentDate.isValid()) ? date : momentDate.format(template);
  }
  return formater;
}

// 每日交易时间
export let tradeTimeSimple = ['09:30', '10:30', '11:30', '14:00', '15:00']
export let tradeTime = ['09:30', '10:00', '10:30', '11:00', '11:30', '13:30', '14:00', '14:30', '15:00']

// 返回距 1970 年 1 月 1 日之间的毫秒数
export function getMsec(time) {
  return (new Date(time.replace(/-/g, '/'))).getTime()
}

// 根据毫米数返回时间
export function getDate(sec) {
  return new Date(sec)
}

// 时间比例尺
export function timeScale(dom, ran) {
  return d3.time.scale()
    .domain(dom)
    .range(ran)
}

// 线性比例尺
export function linear(dom, ran) {
  return d3.scale.linear()
    .domain(dom)
    .range(ran)
}

// 序数比例尺
export function ordinal(dom, ran) {
  return d3.scale.ordinal()
    .domain(dom)
    .range(ran)
}

// 坐标轴
export function axis(scaleVal, direction, type) {
  return d3.svg.axis()
    .scale(scaleVal)
    // .ticks(n)
    .tickSize(0, 0)
    .orient(direction)
    .tickFormat(function (d) {
      if (type === '%') {
        return `${formatVal(d)}%`
      } else {
        return d === '' || isNaN(Number(d)) === true ? `${d}` : formatVal(d)
      }
    })
}

export function formatVal(val) {
  if (typeof (val) === 'number') {
    if (Math.abs(val) < 1000) {
      return val.toFixed(2)
    } else if (Math.abs(val) < 10000) {
      return Math.floor(val)
    } else if (Math.abs(val) < 1000000) {
      return `${(val / 10000).toFixed(2)}万`
    } else if (Math.abs(val) < 10000000) {
      return `${(val / 10000).toFixed(1)}万`
    } else {
      return Math.abs(val) > 100000000 ? `${(val / 100000000).toFixed(1)}亿` : `${(val / 10000).toFixed(0)}万`
    }
  } else {
    return val
  }
}

// 获取最大值
export function max(arr, prop) {
  return d3.max(arr, (d) => {
    return d[prop]
  })
}

// 获取最小值
export function min(arr, prop) {
  return d3.min(arr, (d) => {
    return d[prop]
  })
}

// 获取最大最小值
export function extent(arr, prop) {
  return d3.extent(arr, (d) => {
    return d[prop]
  })
}

// 线生成器
export function line(scaleX, scaleY, time, y) {
  return d3.svg.line()
    .x((d) => {
      // => 兼容safari
      let newTime = d[time].replace(/-/g, '/')
      return scaleX((new Date(newTime).getTime()))
    })
    .y((d) => {
      return scaleY(d[y])
    })
}
// 面积生成器
export function area(scaleX, scaleY, time, y, h) {
  return d3.svg.area()
    .x((d, i) => {
      // => 兼容safari
      let newTime = d[time].replace(/-/g, '/')
      return scaleX((new Date(newTime).getTime()))
    })
    .y0(h)
    .y1((d) => {
      return scaleY(d[y])
    })
}

// 定义线性渐变
export function linearGradient(svg, id, startColor, endColor) {
  let defs = svg.append('defs')

  let linearGradientEl = defs.append('linearGradient')
    .attr('id', id)
    .attr('x1', '0%')
    .attr('y1', '0%')
    .attr('x2', '0%')
    .attr('y2', '100%')

  linearGradientEl.append('stop')
    .attr('offset', '0%')
    .style('stop-color', startColor.toString())

  linearGradientEl.append('stop')
    .attr('offset', '100%')
    .style('stop-color', endColor.toString())

  return linearGradientEl
}

// 定义放射性渐变
export function radialGradient(svg, id, startColor, endColor) {
  let defs = svg.append('defs')

  let radialGradientEl = defs.append('radialGradient')
    .attr('id', id)
    .attr('cx', '50%')
    .attr('cy', '50%')
    .attr('r', '50%')
    .attr('fx', '50%')
    .attr('fy', '50%')

  radialGradientEl.append('stop')
    .attr('offset', '0%')
    .style('stop-color', startColor.toString())
    .style('stop-opacity', 0.8)

  radialGradientEl.append('stop')
    .attr('offset', '100%')
    .style('stop-color', endColor.toString())
    .style('stop-opacity', 0)

  return radialGradientEl
}

// 定义SVG滤镜 高斯模糊
export function gaussianBlur(svg, id) {
  let defs = svg.append('defs')

  let filter = defs.append('filter')
    .attr('id', id)

  let gaussianBlurEl = filter.append('feGaussianBlur')
    .attr('in', 'SourceGraphic')
    .attr('stdDeviation', 5)

  return gaussianBlurEl
}

/**
 * 获取画布容器大小
 */
export function getSvgSize(param, margin) {
  // console.log('%c param', 'color:#f00', param)
  let dom = document.getElementById(`${param.id}`)
  let width = dom.offsetWidth
  let height = dom.offsetHeight

  let svgArgs = {
    id: param.id,
    theme: param.theme || 0,
    margin: margin,
    width: width,
    height: height
  }
  return svgArgs
}

// 创建SVG
export function createSVG(svgArgs) {
  d3.select(`#${svgArgs.id} svg`).remove()
  let svg = d3.select(`#${svgArgs.id}`).append('svg')
    .attr('width', svgArgs.width + svgArgs.margin.left + svgArgs.margin.right)
    .attr('height', svgArgs.height + svgArgs.margin.top + svgArgs.margin.bottom)

  return svg
}

// 生成一个连续数组
export function getSerialArr(nums) {
  let arr = []
  for (let i = 0; i <= nums; i++) {
    arr.push(i)
  }
  return arr
}

/**
 * 绘制网格
 * gridG  => 网格容器
 * svgArgs  => svg参数
 * hNums => 水平线根数
 * vNums => 竖直线根数
 * gridGargs => 网格线参数 width, height, top, bottom, left, right, stroke
 */
export function drawGrid(gridG, svgArgs, hNums, vNums, gridGargs) {
  let hArr = getSerialArr(hNums)
  let vArr = getSerialArr(vNums)
  let w = gridGargs.width
  let h = gridGargs.height

  let update1 = gridG.selectAll(`#${svgArgs.id} .horizontalLines`)
    .data(hArr)
  let enter1 = update1.enter()
  let exit1 = update1.exit()
  // 网格水平分隔线
  update1.attr('class', 'horizontalLines')
    .attr('stroke', gridGargs.stroke)
    .attr('d', function (d, i) {
      return `M0,${(i * (h / hNums))}L${w},${(i * (h / hNums))}`
    })
  enter1.append('path')
    .attr('class', 'horizontalLines')
    .attr('shape-rendering', 'crispEdges')
    .attr('stroke', gridGargs.stroke)
    .attr('stroke-Width', 1)
    .attr('fill', 'none')
    .attr('d', function (d, i) {
      return `M0,${(i * (h / hNums))}L${w},${(i * (h / hNums))}`
    })
  exit1.remove()
  // 网格垂直分隔线
  let update2 = gridG.selectAll(`#${svgArgs.id} .verticalLines`)
    .data(vArr)
  let enter2 = update2.enter()
  let exit2 = update2.exit()
  update2.attr('stroke', gridGargs.stroke)
    .attr('d', function (d, i) {
      return `M${(i * (w / vNums))},0L${(i * (w / vNums))},${h}`
    })
  enter2.append('path')
    .attr('class', 'verticalLines')
    .attr('shape-rendering', 'crispEdges')
    .attr('stroke', gridGargs.stroke)
    .attr('stroke-Width', 1)
    .attr('fill', 'none')
    .attr('d', function (d, i) {
      return `M${(i * (w / vNums))},0L${(i * (w / vNums))},${h}`
    })
  exit2.remove()
}

/**
 * 添加容器
 */
export function drawG(G, args) {
  return G.append('g')
    .attr(args)
}

/**
 * 绘制矩形
 * G => 容器
 * rectArgs => 参数{'class': '', 'x': 0, 'y': 0, 'width': 0, 'height': 0, 'fill': 'none'}
 */
export function drawRect(G, rectArgs) {
  return G.append('rect')
    .attr('shape-rendering', 'crispEdges')
    .attr(rectArgs)
}

/**
 * 添加文字
 * G => 容器
 * textArgs => 参数
 */
export function drawText(G, textArgs) {
  return G.append('text')
    .attr('shape-rendering', 'crispEdges')
    .attr(textArgs)
}

/**
 * 绘制具有区域颜色的折线图
 * G => 容器
 * areaArgs => 参数{'class': '', 'fill', ''}
 * data => 绘图数据
 * area => 面积生成器
*/
export function drawAreaPolyline(G, areaArgs, data, area, svgArgs) {
  let update = G.selectAll(`#${svgArgs.id} .${areaArgs.class}`)
    .data(data)
  let enter = update.enter()
  let exit = update.exit()

  update.attr('d', area)
  // .attr(areaArgs)
  enter.append('path')
    .attr('d', area)
    .attr(areaArgs)
  exit.remove()
}

/**
 * 绘制曲线
 * G => 容器
 * polylineArgs => 参数
 * data => 绘图数据
 * line => 线生成器
 */
export function drawPolyline(G, polylineArgs, data, line, svgArgs) {

  let update = G.selectAll(`#${svgArgs.id} .${polylineArgs.class}`)
    .data(data)
  let enter = update.enter()
  let exit = update.exit()

  update.attr('d', line)
  // .attr(polylineArgs)
  enter.append('path')
    .attr('d', line)
    .attr(polylineArgs)
  exit.remove()
}

/**
 * 绘制柱状图
 * G => 容器
 * rectArgs => 参数
 * data => 绘图数据
 */
export function drawHistogram(G, rectArgs, data, type, scaleX, scaleY, h, red, green, svgArgs) {
  let update = G.selectAll(`#${svgArgs.id} .${rectArgs.class}`)
    .data(data)
  let enter = update.enter()
  let exit = update.exit()

  update
    .attr(rectArgs)
    .attr('x', (d, i) => {
      return scaleX((new Date(d.time.replace(/-/g, '/'))).getTime())
    })
    .attr('y', (d, i) => {
      return h - scaleY(d[type])
    })
    .attr('height', (d, i) => {
      return scaleY(d[type])
    })
    .attr('fill', (d, i) => {
      return d.close - d.open >= 0 ? red : green
    })
  enter.append('rect')
    .attr('shape-rendering', 'crispEdges')
    .attr(rectArgs)
    .attr('x', (d, i) => {
      return scaleX((new Date(d.time.replace(/-/g, '/'))).getTime())
    })
    .attr('y', (d, i) => {
      return h - scaleY(d[type])
    })
    .attr('height', (d, i) => {
      return scaleY(d[type])
    })
    .attr('fill', (d, i) => {
      return d.close - d.open >= 0 ? red : green
    })
  exit.remove()
}

/**
 * 绘制呼吸灯
 * G => 容器
 * lampArgs => 参数
 */
export function drawBreathLamp(G, lampArgs) {
  let breathLamp = G.append('circle')
    .attr(lampArgs)

  return breathLamp
}

/**
 * 绘制一条直线
 * G => 容器
 * lineArgs => 参数
 */
export function drawLine(G, lineArgs) {
  let line = G.append('line')
    .attr('shape-rendering', 'crispEdges')
    .attr(lineArgs)

  return line
}

/**
 * ================================================
 * 以下k线图部分
 * ================================================
 */

/**
 * k线各指标容器模版
 * G => 容器
 */
export function drawBox({ G, gArgs, w, h, color }) {
  let g = G.append('g')
    .attr(gArgs)

  g.append('rect')
    .attr('shape-rendering', 'crispEdges')
    .attr({
      class: 'head',
      x: 0,
      y: 0,
      width: w,
      height: h,
      stroke: 'none',
      fill: color
    })

  return g
}

/**
 * k线各指标设置按钮与关闭按钮
 * G => 容器
 */
export function drawBtn({ G, className, offsetW, offsetH, d, color, scaleX, scaleY, opacity = 1 }) {
  return G.append('g')
    .attr({
      class: className,
      opacity: opacity,
      transform: `translate(${offsetW}, ${offsetH})`
    })
    .append('path')
    .attr({
      d: d,
      fill: color,
      transform: `scale(${scaleX}, ${scaleY})`
    })
}

/**
 * 绘制k线网格之中间的竖直线 => 需要每根竖直线正好位于相近k线中间
 */
export function drawkGrid(G, vNums, rectW, rectS, gridGargs, svgArgs) {
  let vArr = getSerialArr(vNums)
  let w = gridGargs.width
  let h = gridGargs.height
  let unitW = w / vNums
  let x = Math.ceil(unitW / (rectW + rectS)) * (rectW + rectS)
  // 网格垂直分隔线
  let update = G.selectAll(`#${svgArgs.id} .kverticalLines`)
    .data(vArr)
  let enter = update.enter()
  let exit = update.exit()
  update
    .attr('stroke', (d, i) => {
      if (i === 0 || i === vNums) {
        return 'none'
      } else {
        return gridGargs.stroke
      }
    })
    .attr('d', function (d, i) {
      return `M${i * x - rectW / 2},0L${i * x - rectW / 2},${h}`
    })
  enter.append('path')
    .attr('class', 'kverticalLines')
    .attr('shape-rendering', 'crispEdges')
    .attr('stroke', (d, i) => {
      if (i === 0 || i === vNums) {
        return 'none'
      } else {
        return gridGargs.stroke
      }
    })
    .attr('stroke-Width', 1)
    .attr('fill', 'none')
    .attr('d', function (d, i) {
      return `M${i * x - rectW / 2},0L${i * x - rectW / 2},${h}`
    })
  exit.remove()
}

/**
 * 绘制K线上下引线
 * G => 容器
 */
export function drawkLeads({ G, data, className, direction, rectWidth, rectSpace, scaleY, red, green, svgArgs }) {
  // k线上下引线部分
  let update = G.selectAll(`#${svgArgs.id} .${className}`)
    .data(data)
  let enter = update.enter()
  let exit = update.exit()

  update
    .attr('x1', (d, i) => {
      return rectSpace + rectWidth / 2 + i * (rectWidth + rectSpace)
    })
    .attr('y1', (d, i) => {
      return direction === 'up'
        ? scaleY(d.high)
        : scaleY(d.low)
    })
    .attr('x2', (d, i) => {
      return rectSpace + rectWidth / 2 + i * (rectWidth + rectSpace)
    })
    .attr('y2', (d, i) => {
      return direction === 'up'
        ? d.close >= d.open
          ? scaleY(d.close)
          : scaleY(d.open)
        : d.close >= d.open
          ? scaleY(d.open)
          : scaleY(d.close)
    })
    .attr('stroke', (d, i) => {
      if (d.close > d.open) {
        return red
      } else if (d.close < d.open) {
        return green
      } else {
        if (i !== 0) {
          if (data[i - 1].close <= d.close) {
            return red
          } else {
            return green
          }
        } else {
          return red
        }
      }
    })

  enter.append('line').attr('class', className)
    .attr('shape-rendering', 'crispEdges')
    .attr('x1', (d, i) => {
      return rectSpace + rectWidth / 2 + i * (rectWidth + rectSpace)
    })
    .attr('y1', (d, i) => {
      return direction === 'up'
        ? scaleY(d.high)
        : scaleY(d.low)
    })
    .attr('x2', (d, i) => {
      return rectSpace + rectWidth / 2 + i * (rectWidth + rectSpace)
    })
    .attr('y2', (d, i) => {
      return direction === 'up'
        ? d.close >= d.open
          ? scaleY(d.close)
          : scaleY(d.open)
        : d.close >= d.open
          ? scaleY(d.open)
          : scaleY(d.close)
    })
    .attr('stroke-width', 1)
    .attr('stroke', (d, i) => {
      if (d.close > d.open) {
        return red
      } else if (d.close < d.open) {
        return green
      } else {
        if (i !== 0) {
          if (data[i - 1].close <= d.close) {
            return red
          } else {
            return green
          }
        } else {
          return red
        }
      }
    })

  exit.remove()
}

/**
 * 绘制K线实体
 * G => 容器
 */
export function drawkRect({ G, data, className, rectWidth, rectSpace, scaleY, red, green, svgArgs }) {
  let update = G.selectAll(`#${svgArgs.id} .${className}`)
    .data(data)
  let enter = update.enter()
  let exit = update.exit()

  update
    .attr('x', (d, i) => {
      return rectSpace + i * (rectWidth + rectSpace)
    })
    .attr('y', (d, i) => {
      if (d.close > d.open) {
        return scaleY(d.close)
      } else {
        return scaleY(d.open)
      }
    })
    .attr('width', rectWidth)
    .attr('height', (d, i) => {
      if (Math.abs(scaleY(d.close) - scaleY(d.open)) !== 0) {
        return Math.abs(scaleY(d.close) - scaleY(d.open)) > 1.5
          ? Math.abs(scaleY(d.close) - scaleY(d.open))
          : 1.5
      } else {
        return 1
      }
    })
    .attr('stroke', (d, i) => {
      if (d.close > d.open) {
        return rectWidth < 2
          ? 'none'
          : red
      } else if (d.close < d.open) {
        return 'none'
      } else {
        if (i !== 0) {
          if (data[i - 1].close <= d.close) {
            return rectWidth < 2
              ? 'none'
              : red
          } else {
            return 'none'
          }
        } else {
          return rectWidth < 2
            ? 'none'
            : red
        }
      }
    })
    .attr('fill', (d, i) => {
      if (d.close > d.open) {
        return rectWidth < 2
          ? red
          : 'none'
      } else if (d.close < d.open) {
        return green
      } else {
        if (i !== 0) {
          if (data[i - 1].close <= d.close) {
            return rectWidth < 2
              ? red
              : 'none'
          } else {
            return green
          }
        } else {
          return rectWidth < 2
            ? red
            : 'none'
        }
      }
    })

  enter.append('rect').attr('class', className)
    .attr('shape-rendering', 'crispEdges')
    .attr('x', (d, i) => {
      return rectSpace + i * (rectWidth + rectSpace)
    })
    .attr('y', (d, i) => {
      if (d.close >= d.open) {
        return scaleY(d.close)
      } else {
        return scaleY(d.open)
      }
    })
    .attr('width', rectWidth)
    .attr('height', (d, i) => {
      if (Math.abs(scaleY(d.close) - scaleY(d.open)) !== 0) {
        return Math.abs(scaleY(d.close) - scaleY(d.open)) > 1.5
          ? Math.abs(scaleY(d.close) - scaleY(d.open))
          : 1.5
      } else {
        return 1
      }
    })
    .attr('stroke', (d, i) => {
      if (d.close > d.open) {
        return rectWidth < 2
          ? 'none'
          : red
      } else if (d.close < d.open) {
        return 'none'
      } else {
        if (i !== 0) {
          if (data[i - 1].close <= d.close) {
            return rectWidth < 2
              ? 'none'
              : red
          } else {
            return 'none'
          }
        } else {
          return rectWidth < 2
            ? 'none'
            : red
        }
      }
    })
    .attr('fill', (d, i) => {
      if (d.close > d.open) {
        return rectWidth < 2
          ? red
          : 'none'
      } else if (d.close < d.open) {
        return green
      } else {
        if (i !== 0) {
          if (data[i - 1].close <= d.close) {
            return rectWidth < 2
              ? red
              : 'none'
          } else {
            return green
          }
        } else {
          return rectWidth < 2
            ? red
            : 'none'
        }
      }
    })
    .on('click', (d) => { console.log(d) })

  exit.remove()
}

/**
 * QSTZ指标绘图
 */
export function drawQSTZ({ G, data, rectWidth, rectSpace, scaleY, svgArgs }) {
  // if (data.dataPoints && data.dataPoints.length != 0) {
  if (data.dataPoints) {
    //  console.log(data)
    let slice = data.slice
    let scaleX = rectWidth + rectSpace
    // 获得各类需求数据
    let arrowData = []        // 三角箭头区绘图数据
    let safeLineData = []     // 安全线绘图数据
    let klineData = []        // 涨停板绘图数据
    let eyeData = []          // 眼睛绘图数据
    let eyeLineData = []      // 眼睛连线绘图数据

    // 重组数组
    data.dataPoints.forEach((oldData) => {
      if(oldData.index){
        oldData.KLine.index = oldData.index
        klineData.push(oldData.KLine)
      }
      if(oldData.arrows){
        arrowData = [...arrowData, ...oldData.arrows]
      }
      if(oldData.safeLine){
        safeLineData.push(oldData.safeLine)
      }
      if(oldData.eye){
         eyeData.push(oldData.eye)
      }
      if(oldData.eye&&oldData.arrows){
        oldData.arrows.forEach((arrow) => {
          arrow.x = oldData.eye.index
          arrow.y = oldData.eye.price
          arrow.moveRight = oldData.eye.moveRight
          eyeLineData.push(arrow)
        })
      }
    })

    // 绘制三角箭头区域
    let arrowPaddingTop = rectWidth / 4     // 箭头上间距
    let arrowUpdate = G.selectAll(`#${svgArgs.id} .arrow`)
      .data(arrowData)
    let arrowEnter = arrowUpdate.enter()
    let arrowExit = arrowUpdate.exit()
    arrowUpdate
      .attr('d', d => {
        let x1 = scaleX * (d.index - slice) + rectSpace + rectWidth / 2
        let y1 = scaleY(d.price) + arrowPaddingTop
        let x2 = -rectWidth / 4
        let y2 = rectWidth / 2
        let x3 = rectWidth / 2
        let y3 = 0
        return `M${x1} ${y1} l${x2} ${y2} l${x3} ${y3} Z`
      })
      .attr('fill', d => d.color)
      .attr('stroke', d => d.color)

    arrowEnter.append('path').attr('class', 'arrow')
      .attr('shape-rendering', 'crispEdges')
      .attr('d', d => {
        let x1 = scaleX * (d.index - slice) + rectSpace + rectWidth / 2
        let y1 = scaleY(d.price) + arrowPaddingTop
        let x2 = -rectWidth / 4
        let y2 = rectWidth / 2
        let x3 = rectWidth / 2
        let y3 = 0
        return `M${x1} ${y1} l${x2} ${y2} l${x3} ${y3} Z`
      })
      .attr('fill', d => d.color)
      .attr('stroke', d => d.color)

    arrowExit.remove()
    let safeLineUpdate = G.selectAll(`#${svgArgs.id} .safeLine`)

    // 绘制安全线
      .data(safeLineData)
    let safeLineEnter = safeLineUpdate.enter()
    let safeLineExit = safeLineUpdate.exit()
    safeLineUpdate
      .attr('x', d => scaleX * (d.start - slice) + rectSpace)
      .attr('y', d => scaleY(d.price))
      .attr('width', d => scaleX * (d.end - d.start))
      .attr('height', 1)
      .attr('fill', d => d.color)


    safeLineEnter.append('rect').attr('class', 'safeLine')
      .attr('x', d => scaleX * (d.start - slice) + rectSpace)
      .attr('y', d => scaleY(d.price))
      .attr('width', d => scaleX * (d.end - d.start))
      .attr('height', 1)
      .attr('fill', d => d.color)

    safeLineExit.remove()

    // 绘制安全线文案
    let safeTextUpdate = G.selectAll(`#${svgArgs.id} .safeText`)
      .data(safeLineData)
    let safeTextEnter = safeTextUpdate.enter()
    let safeTextExit = safeTextUpdate.exit()
    safeTextUpdate
      .attr('x', d => scaleX * (d.end - slice) + rectSpace)
      .attr('y', d => scaleY(d.price))
      .attr('font-size', '12px')
      .attr('fill', d => d.color)
      .text('保护位')


    safeTextEnter.append('text').attr('class', 'safeText')
      .attr('x', d => scaleX * (d.end - slice) + rectSpace)
      .attr('y', d => scaleY(d.price))
      .attr('font-size', '12px')
      .attr('fill', d => d.color)
      .text('保护位')

    safeTextExit.remove()

    // 绘制涨停板区域
    let klineUpdate = G.selectAll(`#${svgArgs.id} .kline`)
      .data(klineData)
    let klineEnter = klineUpdate.enter()
    let klineExit = klineUpdate.exit()

    klineUpdate
      .attr('x', d => scaleX * (d.index - slice) + rectSpace)
      .attr('y', d => scaleY(d.end))
      .attr('width', d => rectWidth)
      .attr('height', d => scaleY(d.start) - scaleY(d.end))
      .attr('fill', d => d.color)

    klineEnter.append('rect').attr('class', 'kline')
      .attr('x', d => scaleX * (d.index - slice) + rectSpace)
      .attr('y', d => scaleY(d.end))
      .attr('width', d => rectWidth)
      .attr('height', d => scaleY(d.start) - scaleY(d.end))
      .attr('fill', d => d.color)

    klineExit.remove()

    // 绘制眼睛
    let eyeUpdate = G.selectAll(`#${svgArgs.id} .eye`)
      .data(eyeData)
    let eyeEnter = eyeUpdate.enter()
    let eyeExit = eyeUpdate.exit()

    eyeUpdate
      .attr('x', (d) => {
        if (d.moveRight == true) {     //判断moveRight是否为true
          d.index = d.index + 0.5
        }
        return scaleX * (d.index - slice) + rectSpace - rectWidth / 2
      })
      .attr('y', d => scaleY(d.price) + rectWidth * 3)
      .attr('width', d => 2 * rectWidth)
      .attr('height', d => 2 * rectWidth)
      .attr('viewBox', '0 0 1024 1024')     //等比例缩放svg图片

    eyeEnter.append('svg').attr('class', 'eye')
      .attr('x', (d) => {
        if (d.moveRight == true) {
          d.index = d.index + 0.5
        }
        return scaleX * (d.index - slice) + rectSpace - rectWidth / 2
      })
      .attr('y', d => scaleY(d.price) + rectWidth * 3)
      .attr('width', d => 2 * rectWidth)
      .attr('height', d => 2 * rectWidth)
      .attr('viewBox', '0 0 1024 1024')     //等比例缩放svg图片

    eyeExit.remove()

    G.selectAll(`#${svgArgs.id} .eye`).append('path')      // 绘制svg眼睛图片
      .attr('d', icons.eye)
      .attr('fill', '#57A6F8')

    // 绘制眼睛与三角区域连线(x1、y1是眼睛位置，x2、y2是箭头位置)
    let eyeLineUpdate = G.selectAll(`.eyeLine`)
      .data(eyeLineData)
    let eyeLineEnter = eyeLineUpdate.enter()
    let eyeLineExit = eyeLineUpdate.exit()
    eyeLineUpdate
      .attr('x1', (d) => {
        if (d.moveRight == true) {     //判断moveRight是否为true
          d.x = d.x + 0.5
        }
        return scaleX * (d.x - slice) + rectSpace + rectWidth / 2
      })
      .attr('y1', d => scaleY(d.y) + rectWidth * 3)
      .attr('x2', d => scaleX * (d.index - slice) + rectSpace + rectWidth / 2)
      .attr('y2', d => scaleY(d.price) + rectWidth * 0.85)
      .attr('stroke', d => d.color)


    eyeLineEnter.append('line').attr('class', 'eyeLine')
      .attr('x1', (d) => {
        if (d.moveRight == true) {     //判断moveRight是否为true
          d.x = d.x + 0.5
        }
        return scaleX * (d.x - slice) + rectSpace + rectWidth / 2
      })
      .attr('y1', d => scaleY(d.y) + rectWidth * 3)
      .attr('x2', d => scaleX * (d.index - slice) + rectSpace + rectWidth / 2)
      .attr('y2', d => scaleY(d.price) + rectWidth * 0.85)
      .attr('stroke', d => d.color)

    eyeLineExit.remove()
  }
}

/**
 * CDFT指标绘图（超跌反弹）
 */
export function drawCDFT({ G, data, rectWidth, rectSpace, scaleY, svgArgs }) {
  // if (data.dataPoints && data.dataPoints.length != 0) {
  let scaleX = rectWidth + rectSpace
  let lowest; // 最小值，防止三角图标挤出边界外
  // 获得需求数据
  let arrowData = []        // 三角箭头区绘图数据
  data.forEach(d => {
    d.icons.forEach((icon,i) => {
      if(i === 0){
        lowest = icon.y
      }
      lowest > icon.y ? lowest = icon.y : lowest = lowest
      arrowData.push(icon)     
    })
  })

  // 绘制三角箭头区域
  let arrowPaddingTop = rectWidth / 4     // 箭头上间距
  let arrowUpdate = G.selectAll(`#${svgArgs.id} .CDFTarrow`)
    .data(arrowData)
  let arrowEnter = arrowUpdate.enter()
  let arrowExit = arrowUpdate.exit()
  arrowUpdate
    .attr('d', d => {
      let x1 = scaleX * d.x + rectSpace + rectWidth / 2
      let y1 = scaleY(d.y) + arrowPaddingTop
      d.y = lowest? y1 = y1 - 2*arrowPaddingTop : y1 = y1
      let x2 = -rectWidth / 2
      let y2 = rectWidth
      let x3 = rectWidth
      let y3 = 0
      if(d.x < 0){
        return
      }else{
        return `M${x1} ${y1} l${x2} ${y2} l${x3} ${y3} Z`
      }
    })
    .attr('fill', d => d.color)
    .attr('stroke', d => d.color)

  arrowEnter.append('path').attr('class', 'CDFTarrow')
    .attr('shape-rendering', 'crispEdges')
    .attr('d', d => {
      let x1 = scaleX * d.x + rectSpace + rectWidth / 2
      let y1 = scaleY(d.y) + arrowPaddingTop
      d.y = lowest ? y1 = y1 - 2 * arrowPaddingTop : y1 = y1
      let x2 = -rectWidth / 2
      let y2 = rectWidth
      let x3 = rectWidth
      let y3 = 0
      if (d.x < 0) {
        return
      } else {
        return `M${x1} ${y1} l${x2} ${y2} l${x3} ${y3} Z`
      }
    })
    .attr('fill', d => d.color)
    .attr('stroke', d => d.color)

  arrowExit.remove()
}

/**
 * MHCL指标绘图（猛虎出笼）
 */
export function drawMHCL({ G, data, rectWidth, rectSpace, scaleY, svgArgs }) {
  let scaleX = rectWidth + rectSpace
  // 绘制矩形区域
  let rectUpdate = G.selectAll(`#${svgArgs.id} .MHCLrect`)
    .data(data)
  let rectEnter = rectUpdate.enter()
  let rectExit = rectUpdate.exit()

  rectUpdate
    .attr('d', d => {
      let x1 = scaleX * d.startX + rectSpace + rectWidth / 2
      let y1 = scaleY(d.endY)
      let x2 = scaleX * d.endX + rectSpace + rectWidth / 2
      let y2 = scaleY(d.endY)
      let x3 = scaleX * d.endX + rectSpace + rectWidth / 2
      let y3 = scaleY(d.startY)
      let x4 = scaleX * d.startX + +rectSpace + rectWidth / 2
      let y4 = scaleY(d.startY)
      if (d.startX < 0) {
        x1 = 0
        x4 = 0
        return `M${x1} ${y1} L${x2} ${y2} L${x3} ${y3} L${x4} ${y4}`
      } else {
        return `M${x1} ${y1} L${x2} ${y2} L${x3} ${y3} L${x4} ${y4} Z`
      }
    })
    .attr("stroke", d => d.color)
    .attr("fill", "none")

  rectEnter.append("path").attr("class", "MHCLrect")
    .attr('d', d => {
      let x1 = scaleX * d.startX + +rectSpace + rectWidth / 2
      let y1 = scaleY(d.endY)
      let x2 = scaleX * d.endX + +rectSpace + rectWidth / 2
      let y2 = scaleY(d.endY)
      let x3 = scaleX * d.endX + +rectSpace + rectWidth / 2
      let y3 = scaleY(d.startY)
      let x4 = scaleX * d.startX + +rectSpace + rectWidth / 2
      let y4 = scaleY(d.startY)
      if (d.startX < 0) {
        x1 = 0
        x4 = 0
        return `M${x1} ${y1} L${x2} ${y2} L${x3} ${y3} L${x4} ${y4}`
      } else {
        return `M${x1} ${y1} L${x2} ${y2} L${x3} ${y3} L${x4} ${y4} Z`
      }
    })
    .attr("stroke", d => d.color)
    .attr("fill", "none")

  rectExit.remove()

  // 绘制文字区域
  let textUpdate = G.selectAll(`#${svgArgs.id} .MHCLtext`)
    .data(data)
  let textEnter = textUpdate.enter()
  let textExit = textUpdate.exit()
  textUpdate
    .attr('x', d => scaleX * d.startX + rectSpace + rectWidth / 2)
    .attr('y', d => scaleY(d.startY))
    .attr('font-size', '12px')
    .attr('transform', d => `translate(${(scaleX * d.endX - scaleX *d.startX)/2 -15}, 12)`)
    .attr('fill', d => d.color)
    .text(d => d.title)

  textEnter.append('text').attr('class', 'MHCLtext')
    .attr('x', d => scaleX * d.startX + rectSpace + rectWidth / 2)
    .attr('y', d => scaleY(d.startY))
    .attr('font-size', '12px')
    .attr('transform', d => `translate(${(scaleX * d.endX - scaleX *d.startX)/2 -15}, 12)`)
    .attr('fill', d => d.color)
    .text(d => d.title)
  
  textExit.remove()  
}

/**
 * JB指标绘图（夹板）
 */
export function drawJB({ G, data, rectWidth, rectSpace, scaleY, svgArgs }) {
  let scaleX = rectWidth + rectSpace
  // 绘制矩形区域
  let rectUpdate = G.selectAll(`#${svgArgs.id} .JBrect`)
    .data(data)
  let rectEnter = rectUpdate.enter()
  let rectExit = rectUpdate.exit()

  rectUpdate
    .attr('d', d => {
      let x1 = scaleX * d.startX + rectSpace + rectWidth / 2
      let y1 = scaleY(d.endY)
      let x2 = scaleX * d.endX + rectSpace + rectWidth / 2
      let y2 = scaleY(d.endY)
      let x3 = scaleX * d.endX + rectSpace + rectWidth / 2
      let y3 = scaleY(d.startY)
      let x4 = scaleX * d.startX + +rectSpace + rectWidth / 2
      let y4 = scaleY(d.startY)
      if (d.startX < 0) {
        x1 = 0
        x4 = 0
        return `M${x1} ${y1} L${x2} ${y2} L${x3} ${y3} L${x4} ${y4}`
      } else {
        return `M${x1} ${y1} L${x2} ${y2} L${x3} ${y3} L${x4} ${y4} Z`
      }
    })
    .attr("stroke", d => d.color)
    .attr("fill", "none")

  rectEnter.append("path").attr("class", "JBrect")
    .attr('d', d => {
      let x1 = scaleX * d.startX + +rectSpace + rectWidth / 2
      let y1 = scaleY(d.endY)
      let x2 = scaleX * d.endX + +rectSpace + rectWidth / 2
      let y2 = scaleY(d.endY)
      let x3 = scaleX * d.endX + +rectSpace + rectWidth / 2
      let y3 = scaleY(d.startY)
      let x4 = scaleX * d.startX + +rectSpace + rectWidth / 2
      let y4 = scaleY(d.startY)
      if (d.startX < 0) {
        x1 = 0
        x4 = 0
        return `M${x1} ${y1} L${x2} ${y2} L${x3} ${y3} L${x4} ${y4}`
      } else {
        return `M${x1} ${y1} L${x2} ${y2} L${x3} ${y3} L${x4} ${y4} Z`
      }
    })
    .attr("stroke", d => d.color)
    .attr("fill", "none")

  rectExit.remove()
}

/**
 * k线曲线生产器
 */
export function kLine({ rectWidth, rectSpace, scaleY, prop }) {
  return d3.svg.line()
    .x(function (d, i) {
      return rectSpace + rectWidth / 2 + i * (rectWidth + rectSpace)
    })
    .y(function (d) {
      return scaleY(d[prop])
    })
    .interpolate('linear')   //线性插值
}

/**
 * 短线量能曲线生产器
 */
export function dxlnLine({ length, rectWidth, rectSpace, scaleY, prop }) {
  return d3.svg.line()
    .x(function (d, i) {
      if(i === 0){
        return rectSpace + rectWidth / 2 + i * (rectWidth + rectSpace)        
      }else if(i === length + 1){
        return rectSpace + rectWidth / 2 + (i-2) * (rectWidth + rectSpace)
      } else{
        return rectSpace + rectWidth / 2 + (i - 1) * (rectWidth + rectSpace)
      }
    })
    .y(function (d) {
      return scaleY(d[prop])
    })
    .interpolate('linear')   //线性插值
}

/**
 * k线移动均线曲线生成器
 */
export function MALine({ rectWidth, rectSpace, scaleY, prop, MAParam, KdataLen, MAdata }) {
  return d3.svg.line()
    .x(function (d, i) {
      let n = MAParam.indexOf(d.periods)
      let diff = KdataLen - MAdata[n].length
      let newIndex = diff > 0 ? i + diff : i
      return rectSpace + rectWidth / 2 + newIndex * (rectWidth + rectSpace)
    })
    .y(function (d) {
      return scaleY(d[prop])
    })
    .interpolate('linear')  //线性插值
}

/**
 * 绘制通用柱状图
 * G => 容器
 */
export function drawRectChart({ G, data, args, svgArgs }) {
  let update = G.selectAll(`#${svgArgs.id} .${args.class}`)
    .data(data)
  let enter = update.enter()
  let exit = update.exit()

  update.attr(args)
  enter.append('rect')
    .attr('shape-rendering', 'crispEdges')
    .attr(args)
  exit.remove()
}

/**
 * 绘制文本
 */
export function drawTexts(G, className, texts, textArgs, fn, svgArgs) {
  let update = G.selectAll(`#${svgArgs.id} .${className}`)
    .data(texts)
  let enter = update.enter()
  let exit = update.exit()

  update.attr(textArgs)
    .text(fn)
  enter.append('text')
    .attr(textArgs)
    .text(fn)
  exit.remove()
}

/**
 * 定义缩放事件
 * scaleExtent 用于设置最小和最大的缩放比例
 * d3.event.translate 是平移的坐标值
 * d3.event.scale 是缩放的值
 */
export function zoom(range, fn) {
  return d3.behavior.zoom()
    .scale(1)
    .scaleExtent(range)
    .on('zoom', fn)
}

/**
 * 定义拖拽事件
 * d3.event.x d3.event.y => 当前鼠标的位置
 */
export function drag(fn) {
  return d3.behavior.drag()
    .on('drag', fn)
}

/**
 * 定义弧线生成器
 */
export function drawArcs({ innerR, outerR, sAngle, eAngle }) {
  return d3.svg.arc()
    .innerRadius(innerR)
    .outerRadius(outerR)
    .startAngle(sAngle * (Math.PI / 180))
    .endAngle(eAngle * (Math.PI / 180))
}

/**
 * 绘制网格
 * gridG  => 网格容器
 * svgArgs  => svg参数
 * hNums => 水平线根数
 * vNums => 竖直线根数
 * gridGargs => 网格线参数 width, height, top, bottom, left, right, stroke
 */
export function drawSlideGrid(gridG, svgArgs, vNums, gridGargs) {
  let vArr = getSerialArr(vNums)
  let w = gridGargs.width
  let h = gridGargs.height

  // 网格垂直分隔线
  let update = gridG.selectAll(`#${svgArgs.id} .slideVerticalLines`)
    .data(vArr)
  let enter = update.enter()
  let exit = update.exit()
  update.attr('stroke', gridGargs.stroke)
    .attr('opacity', (d, i) => {
      return i !== 0 && i !== vNums ? 1 : 0
    })
    .attr('d', function (d, i) {
      return `M${(i * (w / vNums))},0L${(i * (w / vNums))},${h}`
    })
  enter.append('path')
    .attr('class', 'slideVerticalLines')
    .attr('shape-rendering', 'crispEdges')
    .attr('stroke', gridGargs.stroke)
    .attr('stroke-Width', 1)
    .attr('fill', 'none')
    .attr('opacity', (d, i) => {
      return i !== 0 && i !== vNums ? 1 : 0
    })
    .attr('d', function (d, i) {
      return `M${(i * (w / vNums))},0L${(i * (w / vNums))},${h}`
    })
  exit.remove()
}

/**
 * 绘制 MACD
 */
export function drawLines({ G, data, svgArgs, args }) {
  let update = G.selectAll(`#${svgArgs.id} .${args.class}`)
    .data(data)
  let enter = update.enter()
  let exit = update.exit()

  update.attr(args)
  enter.append('line')
    .attr('shape-rendering', 'crispEdges')
    .attr(args)
  exit.remove()
}

/**
 * 绘制 GJHY箭头
 */
export function drawArrow(G,data,rectWidth,rectSpace,scale) {
  if(data){
    let update = G.selectAll('.GJHYchart .gjhy-arrow')
    .data(data)
    let enter = update.enter()
    let exit = update.exit()
    update.attr("d", (d) => {
      d.x = d.x*(rectWidth + rectSpace) + rectSpace + rectWidth/2
      d.y = scale(d.y)
      if(d.icon === "up_arrow"){
        let x1 = d.x;
        let y1 = d.y - 5
        let x2 = d.x + 5
        let y2 = d.y + 5
        let x3 = d.x - 5
        let y3 = d.y + 5
        return `M ${x1} ${y1} L ${x2} ${y2} L ${x3} ${y3}`
      }else{
        let x1 = d.x
        let y1 = d.y + 5
        let x2 = d.x - 5
        let y2 = d.y - 5
        let x3 = d.x + 5
        let y3 = d.y - 5
        return `M ${x1} ${y1} L ${x2} ${y2} L ${x3} ${y3}`  
      }
    })
      .attr("fill", d => d.color)
    enter.append('path')
      .attr("class", "gjhy-arrow")
      .attr("d", d => {
        d.x = d.x * (rectWidth + rectSpace) + rectSpace + rectWidth/2
        d.y = scale(d.y)
        if (d.icon === "up_arrow") {
          let x1 = d.x;
          let y1 = d.y - 5
          let x2 = d.x + 5
          let y2 = d.y + 5
          let x3 = d.x - 5
          let y3 = d.y + 5
          return `M ${x1} ${y1} L ${x2} ${y2} L ${x3} ${y3}`
        } else {
          let x1 = d.x
          let y1 = d.y + 5
          let x2 = d.x - 5
          let y2 = d.y - 5
          let x3 = d.x + 5
          let y3 = d.y - 5
          return `M ${x1} ${y1} L ${x2} ${y2} L ${x3} ${y3}`
        }
      })
      .attr("fill", d => d.color)
    // .attr(args)
    exit.remove()
  }
  
}

/**
 * 绘制 LNHY图标
 */
export function drawLNHYicon(G, data, rectWidth, rectSpace, scale) {
  let update = G.selectAll('.lnhy_icon')
    .data(data)
  let enter = update.enter()
  let exit = update.exit()

  update.attr("x", d => d.x * (rectWidth + rectSpace) + rectSpace + rectWidth / 2 - 7) 
    .attr("y", d => d.y < 0 ? scale(0) - 16 : scale(0) + 2)
    .attr("width", "14")
    .attr("height", "14")
    .attr("xlink:href", d => {
      let img = d.icon
      return `/static/images/lnhy_${img}.png`
    })

  enter.append("image")
    .attr("class",`lnhy_icon`)
    .attr("xlink:href", d => {
      let img = d.icon
      return `/static/images/lnhy_${img}.png`
    })
    .attr("x", d => d.x * (rectWidth + rectSpace) + rectSpace + rectWidth / 2 - 7) 
    .attr("y", d => d.y < 0 ? scale(0) - 16: scale(0) + 2)
    .attr("width", "14")
    .attr("height", "14")

  exit.remove()
}
